package multiThread;

import gui.MainWindow;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

import javax.swing.JProgressBar;

import controller.MonteCarloSimulation;

public class MonteCarloMultiThread {
	
	public static final int nSimulations = 100000;
	private MainWindow mw;
	
	public MonteCarloMultiThread(MainWindow mw){
		this.mw = mw;
	}
	
	public void call() throws InterruptedException, ExecutionException{
		
		final String CallPutFlag = (String) this.mw.callPutFlag.getSelectedItem();
		final Double S = Double.valueOf((String)this.mw.s.getSelectedItem());
		final Double X = Double.valueOf((String)this.mw.x.getSelectedItem());
		final Double T = Double.valueOf((String)this.mw.t.getSelectedItem());
		final Double r = Double.valueOf((String)this.mw.r.getSelectedItem());
		final Double b = Double.valueOf((String)this.mw.b.getSelectedItem());
		final Double v = Double.valueOf((String)this.mw.v.getSelectedItem());
		final int nSteps = Integer.valueOf((String)this.mw.nSteps.getSelectedItem());
		this.mw.pb.setValue(0);
		
		double start = System.currentTimeMillis();
		final int numberOfCores = Runtime.getRuntime().availableProcessors();
	    final double blockingCoefficient = 0.9;
	    final int poolSize = (int)(numberOfCores / (1 - blockingCoefficient));
	    
	    System.out.println("Number of Cores available is " + numberOfCores);
	    System.out.println("Pool size is " + poolSize);
	    
	    final ExecutorService pool = Executors.newFixedThreadPool(poolSize);
	    final List<Callable<Double>> calculations = new ArrayList<Callable<Double>>();
	    List<Future<Double>> returnValues = null;
	    
	    for(int i= 0 ; i< nSimulations ; i++) 
	    {
	      calculations.add(new Callable<Double>() {
					        public Double call()
					        {
					        	return MonteCarloSimulation.singleSimulation(CallPutFlag, S,
										X, T, r, b, v, nSteps);
					        }        
			      		});
	    }
	    
	    returnValues = pool.invokeAll(calculations, 10000, TimeUnit.SECONDS);
	    double Sum = 0;
	    for(int i=0; i< returnValues.size() ; i++)
		{
			Sum = Sum + returnValues.get(i).get();
			mw.pb.setValue(Math.round(i*100/nSimulations));
			
		}
	    
	    pool.shutdown();
	    
	    double sum = MonteCarloSimulation.average(r, T, Sum, nSimulations);
	    double end = System.currentTimeMillis();
		mw.pb.setValue(100);
		
		mw.result.setText("Result : "+sum );
		mw.time.setText("Run time: " + (end-start)/1000 + " s");
	}
}
